package com.nineclock.sign.service.impl;

import java.math.BigDecimal;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.filter.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.DateTimeUtil;
import com.nineclock.sign.dto.DepartmentDTO;
import com.nineclock.sign.dto.SignDto;
import com.nineclock.sign.dto.SignInfoDTO;
import com.nineclock.sign.dto.SignsDto;
import com.nineclock.sign.excele.CustomHandler;
import com.nineclock.sign.mapper.SignCountMapper;
import com.nineclock.sign.dto.*;
import com.nineclock.sign.mapper.SignInfoMapper;
import com.nineclock.sign.mapper.SignPictureMapper;
import com.nineclock.sign.pojo.SignInfo;
import com.nineclock.sign.pojo.SignPicture;
import com.nineclock.sign.service.SignInfoService;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.feign.SysCompanyUserFeign;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.text.SimpleDateFormat;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class SignInfoServiceImpl implements SignInfoService {
    @Autowired
    private SignInfoMapper signInfoMapper;
    @Autowired
    private SignPictureMapper signPictureMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private SysCompanyUserFeign sysCompanyUserFeign;
    @Autowired
    private SignCountMapper signCountMapper;

    /**
     * 接口名称：APP: 签到
     * 接口路径：POST/sign/insert
     * 刘建
     *
     * @param signInfoDTO
     */
    @Override
    public void sign(SignInfoDTO signInfoDTO) {
        //1. 将签到数据保存到数据库
        //2. 将签到的图片阿里云地址保存到签到图片表中
        //3. 记录/更新用户当日签到次数 ---> 考虑使用redis存储
        //4. 记录/更新用户当月签到次数 ---> 考虑使用redis存储
        //1.1参数校验
        if (signInfoDTO == null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        //封装签到信息
        SignInfo signInfo = new SignInfo();

        // 2.1 设置基本信息，员工id、公司id、创建时
        signInfo.setCompanyId(CurrentUserHolder.get().getCompanyId());
        signInfo.setCompanyUserId(CurrentUserHolder.get().getCompanyUserId());
        signInfo.setCreateTime(new Date());
        signInfo.setLat(signInfoDTO.getLat());
        signInfo.setLng(signInfoDTO.getLng());
        signInfo.setAddress(signInfoDTO.getAddress());
        signInfo.setRemark(signInfoDTO.getRemark());
        signInfo.setVisit(signInfoDTO.getVisit());
        signInfo.setImei(signInfoDTO.getImei());
        //设置签到时间
        Date now = new Date();
        signInfo.setCreateDate(DateTimeUtil.dateToStr(now, DateTimeUtil.TIME_FORMAT_2));
        signInfo.setCreateMonth(DateTimeUtil.dateToStr(now, DateTimeUtil.TIME_FORMAT_4));
        signInfoMapper.insert(signInfo);

        String allImagesUrl = signInfoDTO.getImages();
        if (allImagesUrl == null) {
            throw new NcException(ResponseEnum.SIGN_DATA_NULL);
        }
        String i = ",";
        String[] split = allImagesUrl.split(i);
        for (String signImagesUrl : split) {
            //保存图片
            SignPicture signPicture = new SignPicture();
            signPicture.setSignId(signInfo.getId());
            signPicture.setUrl(signImagesUrl);
            signPictureMapper.insert(signPicture);
        }
        //查询当天的签到次数
        LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SignInfo::getCompanyUserId, CurrentUserHolder.get().getCompanyUserId());
        wrapper.eq(SignInfo::getCreateDate, DateTimeUtil.dateToStr(now, DateTimeUtil.TIME_FORMAT_2));
        Integer count = signInfoMapper.selectCount(wrapper);
        redisTemplate.opsForValue().set(CurrentUserHolder.get().getCompanyId() + CurrentUserHolder.get().getCompanyUserId() + DateTimeUtil.dateToStr(now, DateTimeUtil.TIME_FORMAT_2), count);
        //查询当天的签到次数
        String s = DateTimeUtil.dateToStr(now, DateTimeUtil.TIME_FORMAT_4);
        LambdaQueryWrapper<SignInfo> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper2.eq(SignInfo::getCompanyUserId, CurrentUserHolder.get().getCompanyUserId());
        wrapper2.eq(SignInfo::getCreateMonth, s);
        Integer count2 = signInfoMapper.selectCount(wrapper2);
        redisTemplate.opsForValue().set(CurrentUserHolder.get().getCompanyId() + CurrentUserHolder.get().getCompanyUserId() + DateTimeUtil.dateToStr(now, DateTimeUtil.TIME_FORMAT_4), count2);
    }


    /**
     * 查询签到列表
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param page      总页数
     * @param pageSize  当前页大小
     * @return 返回查询结果
     */
    @Override
    public PageResult<List<SignDto>> querySigns(String startTime, String endTime, Integer page, Integer pageSize) {
        // 构建参数
        // 1.获取起止日期内(包含起止日期)，所有日期的集合
        List<String> spanDateList = DateTimeUtil.getSpanDateList(startTime, endTime);
        LambdaQueryWrapper<SignInfo> wrepper = new LambdaQueryWrapper<>();
        wrepper.select(SignInfo::getCompanyUserId);
        wrepper.gt(SignInfo::getCreateDate, startTime);
        wrepper.lt(SignInfo::getCreateDate, endTime);
        wrepper.groupBy(SignInfo::getCompanyUserId);



        // 创建分页对象
        Page<SignInfo> signInfoPage = new Page<>(page, pageSize);
        Page<SignInfo> infoPage = signInfoMapper.selectPage(signInfoPage, wrepper);
        // 取出当页数据
        List<SignInfo> signInfoList = signInfoPage.getRecords();

        if (CollectionUtils.isEmpty(signInfoList)) {
            throw new NcException(ResponseEnum.USER_NOT_FOUND);
        }


        // 完整返回参数
        List<SignDto> signInfoDtoList = signInfoList.stream().map(signInfo -> {

            SignDto signInfoDto = new SignDto();

            DepartmentDTO DepartmentDTO = new DepartmentDTO();

            // 根据员工id查询员工信息
            SysCompanyUserDTO sysCompanyUserDTO = sysCompanyUserFeign.queryDepartmenByCompanyUserId(signInfo.getCompanyUserId()).getData();


            List<SignsDto> signsDtos = new ArrayList<>();
            //当前用户签到数据
            for (String date : spanDateList) {
                SignsDto signsDto = new SignsDto();
                Integer count = signInfoMapper.countGroup(date, sysCompanyUserDTO.getId());
                signsDto.setSignDate(date);
                signsDto.setSignCount(count);
                signsDtos.add(signsDto);
            }

            signInfoDto.setSigns(signsDtos);

            //插入数据

            DepartmentDTO.setId(sysCompanyUserDTO.getDepartmentId());

            DepartmentDTO.setName(sysCompanyUserDTO.getDepartmentName());

            signInfoDto.setDepartment(DepartmentDTO);

            signInfoDto.setId(signInfo.getCompanyUserId().intValue());

            signInfoDto.setPost(sysCompanyUserDTO.getPost());
            signInfoDto.setUsername(sysCompanyUserDTO.getUserName());
            signInfoDto.setWorkNumber(sysCompanyUserDTO.getWorkNumber());
            wrepper.eq(SignInfo::getCompanyUserId, signInfo.getCompanyUserId());


            return signInfoDto;
        }).collect(Collectors.toList());

        return new PageResult(signInfoPage.getTotal(), signInfoPage.getPages(), signInfoDtoList);
    }

    /**
     * APP: 获取团队员工打卡列表
     *
     * @param dateStr
     * @return
     */
    @Override
    public List<StatisticsTeamSignInDto> listSignAllUser(String dateStr) {
        //用户Id去重
        LambdaQueryWrapper<SignInfo> signInfoWrapper = new LambdaQueryWrapper<>();
        signInfoWrapper.eq(SignInfo::getCreateDate, dateStr).select(SignInfo::getCompanyUserId).groupBy(SignInfo::getCompanyUserId);
        List<SignInfo> signInfos = signInfoMapper.selectList(signInfoWrapper);

        //查询签到表，根据企业Id,当天日期和用户去重Id
        return signInfos.stream().map(signInfo -> {
            //创建statisticsTeamSignInDtos
            StatisticsTeamSignInDto statisticsTeamSignInDtos = new StatisticsTeamSignInDto();
            //查询签到表，根据企业Id,当天日期和用户去重Id

            LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SignInfo::getCreateDate, dateStr);
            wrapper.eq(SignInfo::getCompanyUserId,signInfo.getCompanyUserId());
            List<SignInfo> signInfosList = signInfoMapper.selectList(wrapper);
            List<SignInfoDTO> signInfoDTOS = BeanHelper.copyWithCollection(signInfosList, SignInfoDTO.class);
            if (CollectionUtils.isEmpty(signInfoDTOS)) {
                throw new NcException(ResponseEnum.SIGN_DATA_NULL);
            }
            LambdaQueryWrapper<SignInfo> checkInTimesWrapper = new LambdaQueryWrapper<>();
            checkInTimesWrapper.eq(SignInfo::getCreateDate,dateStr)
                    .eq(SignInfo::getCompanyId,CurrentUserHolder.get().getCompanyId())
                    .eq(SignInfo::getCompanyUserId,signInfo.getCompanyUserId());
            Integer checkInTimes = signInfoMapper.selectCount(checkInTimesWrapper);
            int index = 0;
            for (SignInfo info : signInfosList) {
                signInfoDTOS.get(index).setCreateTime(new SimpleDateFormat("HH:mm:ss").format(info.getCreateTime()));
                signInfoDTOS.get(index).setDayCount(String.valueOf(checkInTimes));
                index++;
            }

            statisticsTeamSignInDtos.setSignResponseList(signInfoDTOS);
            //调用feign查询打卡用户
            SysCompanyUserDTO sysCompanyUserDTO = sysCompanyUserFeign.queryDepartmenByCompanyUserId(signInfo.getCompanyUserId()).getData();
            //set签到用户名
            statisticsTeamSignInDtos.setUsername(sysCompanyUserDTO.getUserName());

            return statisticsTeamSignInDtos;
        }).collect(Collectors.toList());
    }


    /*接口名称：APP: 获取当前用户当天签到次数
     *  接口路径：GET/sign/getDayCount
     */
    @Override
    public int queryDaySign() {
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        Long companyId = CurrentUserHolder.get().getCompanyId();
        int DayCount = signCountMapper.queryDaySign(companyUserId,companyId);

        return DayCount;

    }


    /**
     * 查询当月签到记录
     *
     * @return
     */
    @Override
    public List<SignInfoDTO> queryMonthSign(String dateStr) {
        //企业id
        Long companyId = CurrentUserHolder.get().getCompanyId();

        //查询当前用户id
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        //查询当前用户名
        String username = CurrentUserHolder.get().getUsername();

        //查询当前用户当月签到记录
        List<SignInfoDTO> monthSign = signCountMapper.queryMonthSign(dateStr, companyUserId, companyId);
        int size = monthSign.size();


        //遍历补全当月签到记录图片等信息
        for (SignInfoDTO dto : monthSign) {
            //获取用户id
            Long id = dto.getId();

            //更改时间精确度到分
            String createTime = dto.getCreateTime();
            createTime = createTime.substring(0,createTime.length()-2);
            dto.setCreateTime(createTime);

            //补全图片
            List<String> querypicture = signCountMapper.querypicture(id);
            dto.setSignPictureUrlList(querypicture);

            //补全用户
            dto.setUserName(username);

            //补全月签到数
            dto.setMonthCount(size+"");

            //补全日签到数
            String createDate = dto.getCreateDate().toString();
            int  today = signCountMapper.queryDaySign2(createDate, companyUserId,companyId);
            String Today = String.valueOf(today);
            dto.setDayCount(Today);
            System.out.println("Today = " + Today);

        }
        return  monthSign;
    }

    @Override
    public void exportSignData(String startTime, String endTime) throws IOException {
        // 1.获取起止日期内(包含起止日期)，所有日期的集合
        List<String> spanDateList = DateTimeUtil.getSpanDateList(startTime, endTime);
        LambdaQueryWrapper<SignInfo> wrepper = new LambdaQueryWrapper<>();
        wrepper.select(SignInfo::getCompanyUserId);
        wrepper.gt(SignInfo::getCreateDate, startTime);
        wrepper.lt(SignInfo::getCreateDate, endTime);
        wrepper.groupBy(SignInfo::getCompanyUserId);
        List<SignInfo> signInfoList = signInfoMapper.selectList(wrepper);
        // 完整返回参数
        List<SignDto> signInfoDtoList = signInfoList.stream().map(signInfo -> {

            SignDto signInfoDto = new SignDto();

            DepartmentDTO DepartmentDTO = new DepartmentDTO();

            // 根据员工id查询员工信息
            SysCompanyUserDTO sysCompanyUserDTO = sysCompanyUserFeign.queryDepartmenByCompanyUserId(signInfo.getCompanyUserId()).getData();
            List<SignsDto> signsDtos = new ArrayList<>();
            //当前用户签到数据
            for (String date : spanDateList) {
                SignsDto signsDto = new SignsDto();
                Integer count = signInfoMapper.countGroup(date, sysCompanyUserDTO.getId());
                signsDto.setSignDate(date);
                signsDto.setSignCount(count);
                signsDtos.add(signsDto);
            }
            signInfoDto.setSigns(signsDtos);

            //插入数据

            DepartmentDTO.setId(sysCompanyUserDTO.getDepartmentId());

            DepartmentDTO.setName(sysCompanyUserDTO.getDepartmentName());

            signInfoDto.setDepartment(DepartmentDTO);

            signInfoDto.setId(signInfo.getCompanyUserId().intValue());

            signInfoDto.setPost(sysCompanyUserDTO.getPost());
            signInfoDto.setUsername(sysCompanyUserDTO.getUserName());
            signInfoDto.setWorkNumber(sysCompanyUserDTO.getWorkNumber());
            wrepper.eq(SignInfo::getCompanyUserId, signInfo.getCompanyUserId());

            return signInfoDto;
        }).collect(Collectors.toList());
        // 2.获取响应对象response，设置文件下载的头信息
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        response.setHeader("Content-disposition", "attachment;filename=Attendance.xls");
        response.setContentType("application/octet-stream;charset=UTF-8");
        response.setCharacterEncoding("utf-8");
        // 3.通过response获取输出流, 并生成的Excel输出
        EasyExcel.write(response.getOutputStream())
                .excelType(ExcelTypeEnum.XLS)
                .head(this.handleHeaders(signInfoDtoList))
                .registerWriteHandler(this.horizontalCellStyleStrategy())
                .registerWriteHandler(new CustomHandler())
                .sheet("考勤记录")
                .doWrite(this.handleData(signInfoDtoList));

    }
    /**
     * 处理每行数据
     * @return
     */
    private List handleData(List<SignDto> signInfoDtoList) {
        List<List<String>> dataList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(signInfoDtoList)){
            //每一行数据
            for (SignDto signDto : signInfoDtoList) {
                // 每一行基本信息
                List<String> rowData = new ArrayList<>();
                rowData.add(signDto.getUsername());
                rowData.add(signDto.getWorkNumber());
                rowData.add(signDto.getDepartment().getName());
                rowData.add(signDto.getPost());
                List<SignsDto> signs = signDto.getSigns();
                if (!CollectionUtils.isEmpty(signs)){
                    for (SignsDto sign : signs) {
                        rowData.add(String.valueOf(sign.getSignCount()));
                    }
                }
                dataList.add(rowData);
            }
        }
        return dataList;
    }

    /**
     * 设置样式
     */
    private HorizontalCellStyleStrategy horizontalCellStyleStrategy() {
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //内容策略 - 水平居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        //设置字体
        WriteFont font = new WriteFont();
        font.setFontName("阿里巴巴普惠体");
        font.setFontHeightInPoints((short) 11);
        contentWriteCellStyle.setWriteFont(font);
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(contentWriteCellStyle, contentWriteCellStyle);
        return horizontalCellStyleStrategy;
    }

    /**
     * 处理表头
     * @return
     */
    private List<List<String>> handleHeaders(List<SignDto> signInfoDtoList) {
        List<List<String>> headers = new ArrayList<>();

        headers.add(Arrays.asList("姓名"));
        headers.add(Arrays.asList("工号"));
        headers.add(Arrays.asList("部门"));
        headers.add(Arrays.asList("职位"));
        if (!CollectionUtils.isEmpty(signInfoDtoList)){
            SignDto signDto = signInfoDtoList.get(0);
            List<SignsDto> signs = signDto.getSigns();
            if (!CollectionUtils.isEmpty(signs)){
                for (SignsDto sign : signs) {
                    headers.add(Arrays.asList(sign.getSignDate()));
                }
            }
        }
        return  headers;
    }


}

